<!DOCTYPE HTML>

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>SlickGrid example 5: Collapsing</title>
  <link rel="stylesheet" href="../slick.grid.css" type="text/css" />
  <link rel="stylesheet" href="../controls/slick.pager.css" type="text/css" />
  <link rel="stylesheet" href="../plugins/slick.headermenu.css" type="text/css" />
  <link rel="stylesheet" href="../plugins/slick.headerbuttons.css" type="text/css" />
  <link rel="stylesheet" href="../css/smoothness/jquery-ui.css" type="text/css" />
  <link rel="stylesheet" href="examples.css" type="text/css" />
  <link rel="stylesheet" href="../css/select2.css" type="text/css" />

  <style>
    .select2-container {
      top: -3px;
      left: -6px;
    }

    .select2-container .select2-selection--single {
      height: 30px;
    }

    .icon-highlight-off,
    .icon-highlight-on {
      background-image: url(../images/bullet_blue.png);
    }

    .icon-highlight-off {
      opacity: 0.2;
    }

    .negative-highlight {
      background: red;
    }

    .cell-title {
      font-weight: bold;
    }

    .cell-effort-driven {
      text-align: center;
    }

    .toggle {
      height: 9px;
      width: 9px;
      display: inline-block;
    }

    .toggle.expand {
      background: url(../images/expand.gif) no-repeat center center;
    }

    .toggle.collapse {
      background: url(../images/collapse.gif) no-repeat center center;
    }

    .slick-header-menu {
      border: 1px solid #718BB7;
      background: #f0f0f0;
      padding: 2px;
      -moz-box-shadow: 2px 2px 2px silver;
      -webkit-box-shadow: 2px 2px 2px silver;
      min-width: 100px;
      z-index: 20;
    }


    .slick-header-menuitem {
      padding: 2px 4px;
      border: 1px solid transparent;
      border-radius: 3px;
    }

    .slick-header-menuitem:hover {
      border-color: silver;
      background: white;
    }

    .slick-header-menuitem-disabled {
      border-color: transparent !important;
      background: inherit !important;
    }

    #contextMenu {
      background: #e1efc7;
      border: 1px solid gray;
      padding: 2px;
      display: inline-block;
      min-width: 100px;
      -moz-box-shadow: 2px 2px 2px silver;
      -webkit-box-shadow: 2px 2px 2px silver;
      z-index: 9999;
    }

    #contextMenu li {
      padding: 4px 4px 4px 14px;
      list-style: none;
      cursor: pointer;
      background: url("../images/arrow_right_peppermint.png") no-repeat center left;
    }

    #contextMenu li:hover {
      background-color: white;
    }

    /*定位*/
    .changed {
      background: pink;
    }

    .current {
      border: 1px solid black;
      background: orange;
    }
  </style>
</head>

<body>
  <table width="100%">
    <tr>
      <td valign="top" width="80%">
        <div style="position:relative">
          <div class="grid-header" style="width:100%">
            <label>stone slick-grid</label>
            <span style="float:right" class="ui-icon ui-icon-search" title="Toggle search panel"
              onclick="toggleFilterRow()"></span>
          </div>

          <div id="myGrid" style="width:100%;height:500px;;"></div>
          <div id="pager" style="width:100%;height:20px;"></div>

          <div id="inlineFilterPanel" style="display:none;background:transparent;padding:3px;color:black;">
            Filter: <input type="text" id="txtSearch2">
            Position:<input type="text" id="txtPosition"><a>Q</a>
            <a>导出EXCEL</a>
          </div>
        </div>
      </td>
      </td>
      <td valign="top">
        <h2>Demonstrates:</h2>
        <ul>
          <li>implementing expand/collapse as a filter for DataView</li>
        </ul>

        <h2>View Source:</h2>
        <ul>
          <li><A href="https://github.com/mleibman/SlickGrid/blob/gh-pages/examples/example5-collapsing.html"
              target="_sourcewindow"> View the source for this example on Github</a></li>
        </ul>

        <h2>TODO:</h2>
        <ul>
          <li>权限控制</li>
          <li>编辑与行选择冲突√</li>
          <li>分组表头存在BUG</li>
          <li>全选√</li>
          <li>导出EXCEL非Text类型的存在问题</li>
          <li>通过属性值定位功能没有完成</li>
          <li>排序功能没有验证</li>
          <li>结合bootStrap样式没有实现</li>
          <li>表格列下拉菜单</li>
          <li>增加行</li>
          <li>删除行</li>
          <li>修改状态</li>
          <li>选择框与区域选择冲突---注册顺序需要注意，最后注册区域选择√</li>
          <li>表头菜单-展开不能自适应位置的问题√</li>
          <li>ctrl+a 全选</li>
          <li>ctrl+z 取消全选</li>
          <li>顶部 设置信息</li>
          <li>各种表格内部控件</li>
          <li>LongText 加载z-index的问题【可以批量编辑】</li>
          <li>滚动到 定位的数据行不正确、data不是数据源中的父子关系数据√</li>
          <li>展开第几层</li>
          <li>表格下拉控件样式√</li>
          <li>权限控制</li>
          <li>立即编辑</li>
          <li>冻结列和锁定和锁定区域必须先等，即分组不能跨冻结列</li>
          <li>带有[D]标识状态删除的不能编辑</li>
          <li>增加子与删除子 设计中。</li>
          <li>解决最后一列列头菜单显示不全的问题</li>
          <li>自动排序编号列去掉表头</li>
          <li>解决和定位冻结列选择问题，原不能跨冻结列选择</li>
          <li>TODO:从右向左存在问题</li>
          <li>区域选择、复制与checkbox表格控件兼容完成</li>
          <li>20210310 区域选择开发完成</li>
          <li>20210311 双击某些编辑框不灵敏</li>
          <li></li>
          <li></li>
          <li></li>
        </ul>
      </td>
    </tr>
  </table>
  <ul id="contextMenu" style="display:none;position:absolute">
    <b>操作:</b>
    <li id='excel' data="excel">export excel</li>
    <li id='scrollRowIntoView' data="search"><input id='scrollRowIntoViewSearch' type="input" style="width: 100px;"
        value="1" />
      <input id='scrollRowIntoViewQuery' type="button" value="Q" />
    </li>
    <li id='addRow'>add row</li>
    <li id='level' data="level">
      <select id='levelOp'>
        <option>ALL</option>
        <option>1</option>
        <option>2</option>
        <option>3</option>
        <option>4</option>
        <option>5</option>
        <option>6</option>
        <option>7</option>
        <option>8</option>
        <option>9</option>
      </select>
    </li>
  </ul>
  <!--https://github.com/rainabba/jquery-table2excel-->
  <script src="../lib/firebugx.js"></script>

  <script src="../lib/jquery-1.7.min.js"></script>

  <script src="../lib/jquery.event.drag-2.2.js"></script>
  <script src="../lib/jquery-ui.min.js"></script>
  <script src="../slick.core.js"></script>
  <script src="../slick.formatters.js"></script>
  <script src="../slick.editors.js"></script>
  <script src="../slick.grid.js"></script>
  <script src="../slick.dataview.js"></script>
  <script src="../plugins/slick.autotooltips.js"></script>
  <script src="../plugins/slick.cellrangedecorator.js"></script>
  <script src="../plugins/slick.cellrangeselector.js"></script>
  <script src="../plugins/slick.cellexternalfullcopymanager.js"></script>
  <script src="../plugins/slick.cellselectionmodel.js"></script>
  <script src="../controls/slick.columnpicker.js"></script>
  <script src="../plugins/slick.headermenu.js"></script>
  <script src="../plugins/slick.headerbuttons.js"></script>
  <script src="../lib/jszip.min.js"></script>
  <script src="../lib/excel-gen.js"></script>
  <script src="../lib/FileSaver.js"></script>
  <script src="../controls/slick.pager.js"></script>
  <script src="../plugins/slick.checkboxselectcolumn.js"></script>
  <script src="../plugins/slick.rowselectionmodel.js"></script>
  <script src="../lib/select2.js"></script>
  <script>
    function requiredFieldValidator(value) {
      if (value == null || value == undefined || !value.length) {
        return { valid: false, msg: "This is a required field" };
      } else {
        return { valid: true, msg: null };
      }
    }

    var mps = {
      M: 'manufactory',
      P: 'purchase'
    }


    function toggleFilterRow() {
      grid.setTopPanelVisibility(!grid.getOptions().showTopPanel);
    }

    // top panel
    $(".grid-header .ui-icon")
      .addClass("ui-state-default ui-corner-all")
      .mouseover(function (e) {
        $(e.target).addClass("ui-state-hover")
      })
      .mouseout(function (e) {
        $(e.target).removeClass("ui-state-hover")
      });

    function PopulateSelect(select, dataSource, addBlank) {
      var index, len, newOption;
      if (addBlank) { select.appendChild(new Option('', '')); }
      $.each(dataSource, function (value, text) {
        newOption = new Option(text, value);
        select.appendChild(newOption);
      });
    };

    // stackoverflow.com/questions/2532218
    function pickRandomProperty(obj) {
      var result;
      var count = 0;
      for (var prop in obj)
        if (Math.random() < 1 / ++count)
          result = prop;
      return result;
    }

    function PopulateSelect(select, dataSource, addBlank) {
      var index, len, newOption;
      if (addBlank) { select.appendChild(new Option('', '')); }
      $.each(dataSource, function (value, text) {
        newOption = new Option(text, value);
        select.appendChild(newOption);
      });
    };

    var TaskNameFormatter = function (row, cell, value, columnDef, dataContext) {
      value = value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
      var spacer = "<span style='display:inline-block;height:1px;width:" + (15 * dataContext["indent"]) + "px'></span> ";
      var idx = dataView.getIdxById(dataContext.id);
      var levelNum = doLevelNum(dataContext["indent"]);
      var item = data[idx + 1];
      if (item && item.indent > item.indent) {
        if (dataContext._collapsed) {
          return spacer + " <span class='toggle expand'></span>&nbsp;" + levelNum + f2000Status(dataContext);
        } else {
          return spacer + " <span class='toggle collapse'></span>&nbsp;" + levelNum + f2000Status(dataContext);
        }
      } else {
        return spacer + " <span class='toggle'></span>&nbsp;" + levelNum + f2000Status(dataContext);
      }
    };

    function doLevelNum(ix) {
      return " [" + (ix + 1) + "] ";
    }

    function f2000Status(data) {
      return "<a " + (data.state ? "style='color:red'" : "") + ">" + data.f2000 + "</a><a>" + (data.state ? "[D]" : "[N]") + '</a>';
    }

    var searchString = "";
    var dataView;
    var grid;
    var levelIx = 0;
    var data = [];
    var groups = [[{ "group": "D", "name": "design", "expend": true }, { "group": "S", "name": "process", "expend": true }, { "group": "G", "name": "other", "expend": true }]];
    var columns = [
      { id: "num", group: ["D"], expend: true },
      { id: "checked", group: ["D"], expend: true },
      { id: "f2000", name: "no", expend: true, group: ["D"], field: "f2000", width: 220, cssClass: "cell-title", formatter: TaskNameFormatter, editor: Slick.Editors.Text, validator: requiredFieldValidator },
      { id: "operator", name: "operator", group: ["D"], field: "operator", width: 100, formatter: CustomerFormatter },
      { id: "f1000", name: "no1", group: ["S"], field: "f1000", width: 200, resizable: false },
      { id: "createTime", name: "create time", group: ["S"], field: "createTime", width: 200, resizable: false, editor: Slick.Editors.Date },
      { id: "f2136", name: "remark", group: ["G"], field: "f2136", minWidth: 200, editor: Slick.Editors.LongText },
      { id: "qty", name: "qty", group: ["G"], field: "qty", minWidth: 80, editor: Slick.Editors.Text },
      { id: "mp", name: "M/P", group: ["G"], width: 80, minWidth: 20, maxWidth: 200, cssClass: "cell-effort-driven", field: "mp", editor: Slick.Editors.Select2Editor, dataSource: mps },
      { id: "oth1", name: "oth1", group: ["G"], field: "oth1", minWidth: 100, editor: Slick.Editors.Text },
      { id: "oth2", name: "oth2", group: ["G"], field: "oth2", minWidth: 400, editor: Slick.Editors.Text },
      { id: "oth3", name: "oth3", group: ["G"], field: "oth3", minWidth: 600, editor: Slick.Editors.Text },
    ];

    var options = {
      editable: true,
      enableAddRow: true,
      enableCellNavigation: true,
      cellHighlightCssClass: "changed",
      cellFlashingCssClass: "current",
      asyncEditorLoading: false,
      frozenColumn: 3,
      headerGroups: groups,
      showHeaderRow: false,
      autoEdit: true,
      rowHeight: 30,
      fileName: function () {
        return "bom.xlsx";
      },
      topPanelHeight: 30
    };

    var percentCompleteThreshold = 0;
    var searchString = "";

    // 过滤
    function myFilter(item, args) {
      if (item.parent != null) {
        var parent = data[item.parent];

        while (parent) {
          if (parent._collapsed) {
            return false;
          }

          parent = data[parent.parent];
        }
      }

      if (args && args.searchString != "" && item["f2000"].indexOf(args.searchString) == -1) {
        return false;
      }

      if (levelIx && levelIx > 0) {
        return item["indent"] < levelIx;
      }

      return true;
    }

    function f2000Sort(a, b) {
      return a["f2000"] - b["f2000"];
    }

    function CustomerFormatter(row, cell, value, columnDef, dataContext) {
      return "<a   class='btnAddPart  cell-a-btn'></a>"
        + " <a   class='btnDeletePart cell-a-btn' ></a > "
        + value
        + "<a class='cell-a-menu' style='border:1px;color:red;margin:3px;'>操作</a >";
    }

    for (var i = 0; i < columns.length; i++) {
      columns[i].header = {
        menu: {
          items: [
            {
              iconImage: "../images/sort-asc.gif",
              title: "Sort Ascending",
              command: "sort-asc"
            },
            {
              iconImage: "../images/sort-desc.gif",
              title: "Sort Descending",
              command: "sort-desc"
            },
            {
              title: "Hide Column",
              command: "hide",
              disabled: true,
              tooltip: "Can't hide this column"
            },
            {
              iconCssClass: "icon-help",
              title: "Filter",
              command: "filter",
              content: " <input style='widht:50px;' value='0'></input>"
            }
          ]
        }
      };
    }

    // 添加行
    function addRow(row) {
      var current = 5;
      var newRow = { title: "new Title", duration: "1 day" };
      var rowData = grid.getData();
      rowData.splice(current, 0, newRow);
      grid.setData(rowData);
      grid.render();
      grid.scrollRowIntoView(current, false);
    }


    $(function () {
      var indent = 0;
      var parents = [];


      $("#excel").bind("click", function () {
        grid.excel();
      });

      $("#scrollRowIntoView").bind("click", function (e) {
        e.stopPropagation();
        e.preventDefault();
      })

      $("#level").bind("click", function (e) {
        e.stopPropagation();
        e.preventDefault();
      })

      $("#levelOp").change(function (e) {
        var optionVal = $("#levelOp option:selected").val();
        if (optionVal == "ALL") {
          levelIx = 0;
        } else {
          levelIx = optionVal;
        }

        updateFilter();
      });

      // 增加行模拟
      $("#addRow").bind("click", function () {
        addRow();
      })

      var lastQ = "";
      var lastIx = -1;
      $("#scrollRowIntoViewQuery").bind("click", function (e) {
        var query = $("#scrollRowIntoViewSearch").val();
        var currentServer = Math.round(Math.random() * (data.length - 1));
        if (lastQ != query) {
          lastIx = -1;
          lastQ = query;
        }
        for (var ix = 0; ix < data.length; ix++) {
          var _i = data[ix]["f2000"] ? data[ix]["f2000"].indexOf(query) : -1;
          if (ix > lastIx && _i > -1) {
            lastIx = ix;
            break;
          }
        }
        grid.scrollRowIntoView(lastIx);
        grid.flashCell(lastIx, grid.getColumnIndex("f2000"), 100);
      })

      // prepare the data
      for (var i = 0; i < 500; i++) {
        var d = (data[i] = {});
        var parent;

        if (Math.random() > 0.8 && i > 0) {
          indent++;
          parents.push(i - 1);
        } else if (Math.random() < 0.3 && indent > 0) {
          indent--;
          parents.pop();
        }

        if (parents.length > 0) {
          parent = parents[parents.length - 1];
        } else {
          parent = null;
        }

        d["id"] = "id_" + i;
        d["indent"] = indent;
        d["parent"] = parent;
        d["operator"] = "Task " + i;
        d["f2000"] = "EYA001" + i % 7 + "_" + i;
        d["f1000"] = "EYA001" + i % 7;
        d["f2136"] = "Keep on going never give up !";
        d["qty"] = i % 7;
        d["createTime"] = '2021-02-24';
        d["mp"] = pickRandomProperty(mps);
        d["state"] = i % 2 == 0;
      }

      // initialize the model
      dataView = new Slick.Data.DataView({ inlineFilters: true });
      dataView.beginUpdate();
      dataView.setItems(data);
      dataView.setFilter(myFilter);
      dataView.endUpdate();

      // initialize the grid
      grid = new Slick.Grid("#myGrid", dataView, columns, options);

      // 编辑
      //可编辑事件失焦前触发的函数
      grid.onBeforeEditCell.subscribe(function (e, args) {
        item = dataView.getItem(args.row);
        if (item.state) {
          return false;
        }
      });
      //可编辑事件失焦后触发的函数
      grid.onBeforeCellEditorDestroy.subscribe(function (e, args) {
        console.log(item);//这里的args与onBeforeEditCell 中的不同，失去焦点之后会把当前行的对象丢失
        item = {};
      });

      grid.onCellChange.subscribe(function (e, args) {
        dataView.updateItem(args.item.id, args.item);
      });

      // pager 
      var pager = new Slick.Controls.Pager(dataView, grid, $("#pager"));

      var checkboxSelector = new Slick.CheckboxSelectColumn({
        cssClass: "slick-cell-checkboxsel"
      });
      grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: false }));
      grid.registerPlugin(checkboxSelector);
      var columnpicker = new Slick.Controls.ColumnPicker(columns, grid, options);

      grid.setSelectionModel(new Slick.CellSelectionModel());
      //grid.setSelectionModel(new Slick.RowSelectionModel());

      grid.registerPlugin(new Slick.AutoTooltips());

      // move the filter panel defined in a hidden div into grid top panel
      $("#inlineFilterPanel")
        .appendTo(grid.getTopPanel())
        .show();

      // wire up the search textbox to apply the filter to the model
      $("#txtSearch,#txtSearch2").keyup(function (e) {
        Slick.GlobalEditorLock.cancelCurrentEdit();

        // clear on Esc
        if (e.which == 27) {
          this.value = "";
        }

        searchString = this.value;
        updateFilter();
      });

      var h_runfilters = null;

      // wire up the slider to apply the filter to the model
      $("#pcSlider,#pcSlider2").slider({
        "range": "min",
        "slide": function (event, ui) {
          Slick.GlobalEditorLock.cancelCurrentEdit();

          if (percentCompleteThreshold != ui.value) {
            window.clearTimeout(h_runfilters);
            h_runfilters = window.setTimeout(updateFilter, 10);
            percentCompleteThreshold = ui.value;
          }
        }
      });

      function updateFilter() {
        dataView.setFilterArgs({
          searchString: searchString
        });
        dataView.refresh();
      }

      var temp = columns[1];
      var gp = columns[1].group;
      columns[1] = checkboxSelector.getColumnDefinition();
      columns[1].group = gp;
      columns[1].expend = true;

      // set keyboard focus on the grid
      grid.getCanvasNode().focus();
      // https://www.cnblogs.com/fszz/articles/5655154.html
      var copyExtManager = new Slick.CellExternalFullCopyManager();
      //grid.registerPlugin(copyManager);
      grid.registerPlugin(copyExtManager);

      // 自定表头按钮
      var headerMenuPlugin = new Slick.Plugins.HeaderMenu({});

      headerMenuPlugin.onBeforeMenuShow.subscribe(function (e, args) {
        var menu = args.menu;

      });

      headerMenuPlugin.onCommand.subscribe(function (e, args) {
        if (args.command == "filter") {
          searchString = args.item.filterValue;
          Slick.GlobalEditorLock.cancelCurrentEdit();
          dataView.refresh();
        }
      });

      grid.registerPlugin(headerMenuPlugin);

      // checkbox
      var checkboxSelector = new Slick.CheckboxSelectColumn({
        cssClass: "slick-cell-checkboxsel"
      });

      grid.onAddNewRow.subscribe(function (e, args) {
        var item = {
          "id": "new_" + (Math.round(Math.random() * 10000)),
          "indent": 0,
          "title": "New task",
          "duration": "1 day",
          "percentComplete": 0,
          "start": "01/01/2009",
          "finish": "01/01/2009",
          "effortDriven": false
        };
        $.extend(item, args.item);
        dataView.addItem(item);
      });


      // key ctrl+a / ctrl+z
      grid.onKeyDown.subscribe(function (e) {

        // select all rows on ctrl-a
        if (!(e.which == 65 || e.which == 90 || e.which == 70) || !e.ctrlKey) {
          return false;
        }

        if (e.which == 65) {
          var rows = [];
          for (var i = 0; i < dataView.getLength(); i++) {
            rows.push(i);
          }
          grid.setSelectedRows(rows);
          e.preventDefault();
        }

        if (e.which == 90) {
          var rows = [];
          grid.setSelectedRows(rows);
          e.preventDefault();
        }

        if (e.which == 70) {
          e.preventDefault();
        }

      });


      // tree toggle
      grid.onClick.subscribe(function (e, args) {
        if ($(e.target).hasClass("toggle")) {
          var item = dataView.getItem(args.row);
          if (item) {
            if (!item._collapsed) {
              item._collapsed = true;
            } else {
              item._collapsed = false;
            }

            dataView.updateItem(item.id, item);
          }
          e.stopImmediatePropagation();
        }
      });

      // contextMenu
      grid.onContextMenu.subscribe(function (e) {
        e.preventDefault();
        var cell = grid.getCellFromEvent(e);
        $("#contextMenu")
          .data("row", cell.row)
          .css("top", e.pageY)
          .css("left", e.pageX)
          .show();
        $("body").one("click", function () {
          $("#contextMenu").hide();
        });
      });

      // wire up model events to drive the grid
      dataView.onRowCountChanged.subscribe(function (e, args) {
        grid.updateRowCount();
        grid.render();
      });

      dataView.onRowsChanged.subscribe(function (e, args) {
        grid.invalidateRows(args.rows);
        grid.render();
      });

      var h_runfilters = null;

      // wire up the slider to apply the filter to the model
      $("#pcSlider").slider({
        "range": "min",
        "slide": function (event, ui) {
          Slick.GlobalEditorLock.cancelCurrentEdit();

          if (percentCompleteThreshold != ui.value) {
            window.clearTimeout(h_runfilters);
            h_runfilters = window.setTimeout(dataView.refresh, 10);
            percentCompleteThreshold = ui.value;
          }
        }
      });
      grid.setOptions({ autoEdit: true });
      // wire up the search textbox to apply the filter to the model
      $("#txtSearch").keyup(function (e) {
        Slick.GlobalEditorLock.cancelCurrentEdit();

        // clear on Esc
        if (e.which == 27) {
          this.value = "";
        }

        searchString = this.value;
        dataView.refresh();
      })
    })
  </script>
</body>

</html>